/*
 * @Author: luoqi
 * @Date: 2023-05-18 15:17:46
 * @ Modified by: luoqi
 * @ Modified time: 2024-03-14 15:06
 */

#ifndef _QLINK_H
#define _QLINK_H

#include <stdint.h>

typedef struct {
    uint16_t sof;
    uint8_t serial;
    uint8_t type;
    uint8_t size;
    uint8_t *data;
    uint16_t crc;
    uint8_t eof;
} QLinkFrame;

typedef int (*QLinkSend)(uint8_t *data, int len);
typedef int (*QLinkRecv)(uint8_t *buf, int len);
typedef struct  {
    uint16_t recvcnt;           // receive byte counter
    QLinkFrame sframe;          // send frame;
    QLinkFrame rframe;          // recv frame cache
    uint8_t rfame_buf_size;     // recv frame buf size
    uint8_t *rbuf;
    uint8_t rbuf_size;

    QLinkSend send;
    QLinkRecv recv;
} QLink;

/**
 * @ brief: initialize a link.
 * @ link: link object.
 * @ send: link send data method.
 * @ recv: link receive data method.
 * @ framebuf: link receive frame data buffer.
 * @ framebufsize: link receive frame data buffer size.
 * @ rbuf: link receive data buffer.
 * @ rbuf_size: link receive data buffer size.
 * @ return: 0 - success,
 *           othere - failed
 */
int qlink_init(QLink *link, QLinkSend send, QLinkRecv recv, uint8_t *framebuf, uint8_t framebuf_size, uint8_t *rbuf, uint8_t rbuf_size);

/**
 * @ brief: send a frame from the link.
 * @ link: qlink object.
 * @ type: data type.
 * @ data: send data.
 * @ size: send data size.
 * @ return: if -1, send head;
 *           if -2, send data error;
 *           if -3, send tail error;
 *           if >0, send frame size
 */
int qlink_send(QLink *link, uint8_t type, uint8_t *data, uint8_t size);

/**
 * @ brief: recvive data from qlink
 * @ link: qlink object.
 * @ size: receive data length.
 * @ return: if -1, receive frame eof error;
 *           if -2, receive frame crc error;
 *           if -3, receive size overflow;
 *           if -4, receive function recv error;
 *           if 0, receive not complete;
 *           if greater than 0, receive complete, and return frame size.
 */
int qlink_recv(QLink *link, uint8_t size);

/**
 * @ brief: package the data to a frame.
 * @ frame: packaged frame.
 * @ type: frame type.
 * @ data: frame data.
 * @ size: frame data size.
 */
int qlink_pack(QLinkFrame *frame, uint8_t type, uint8_t *data, uint8_t size);

/**
 * @ brief: unpack data from input data
 * @ link: qlink object.
 * @ size: input data length.
 * @ return: if -1, receive frame eof error;
 *           if -2, receive frame crc error;
 *           if -3, receive size overflow;
 *           if 0, receive not complete;
 *           if greater than 0, receive complete, and return frame size.
 */
int qlink_unpack(QLink *link, uint8_t *input, int size);

#endif
